package com.imooc.framework.thread;

import java.util.concurrent.locks.StampedLock;

public class StampedLockDemo implements Runnable {

    private final StampedLock stampedLock = new StampedLock();

    private double x;
    private double y;

    public void move(double deltaX, double deltaY) {
        long stamp = stampedLock.writeLock(); // 获取写锁
        try {
            x += deltaX;
            y += deltaY;
        } finally {
            stampedLock.unlockWrite(stamp); // 释放写锁
        }
    }

    public double distanceFromOrigin() {
        long stamp = stampedLock.tryOptimisticRead(); // 获得一个乐观读锁

        // 注意下面两行代码不是原子操作
        // 假设x,y = (100,200)
        double currentX = x;
        // 此处已读取到x=100，但x,y可能被写线程修改为(300,400)
        double currentY = y;
        // 此处已读取到y，如果没有写入，读取是正确的(100,200)
        // 如果有写入，读取是错误的(100,400)
        System.out.println(Thread.currentThread().getName() + " 执行乐观锁" + "x=" + x + " y=" + y);
        if (!stampedLock.validate(stamp)) { // 检查乐观读锁后是否有其他写锁发生

            stamp = stampedLock.readLock(); // 获取一个悲观读锁
            try {
                currentX = x;
                currentY = y;
                System.out.println(Thread.currentThread().getName() + " 执行悲观锁" + "x=" + x + " y=" + y);
            } finally {
                stampedLock.unlockRead(stamp); // 释放悲观读锁
            }
        }
        return Math.sqrt(currentX * currentX + currentY * currentY);
    }

    @Override
    public void run() {

        distanceFromOrigin();
//        move(10,10);
    }

    public static void main(String[] args) {
        StampedLockDemo stampedLockDemo = new StampedLockDemo();
        Thread t1 = new Thread(stampedLockDemo);
        Thread t2 = new Thread(stampedLockDemo);
        Thread t3 = new Thread(stampedLockDemo);
        Thread t4 = new Thread(stampedLockDemo);
        t1.setName("thread1");
        t2.setName("thread2");
        t3.setName("thread3");
        t4.setName("thread4");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}
